package com.tifa.myssm.ioc.impl;

import com.tifa.myssm.ioc.BeanFactory;
import org.apache.commons.lang3.StringUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

public class ClassPathXmlApplicationContext implements BeanFactory {
    private Map<String, Object> hashObject = new HashMap<>();

    public ClassPathXmlApplicationContext() {
        this("applicationContext.xml");
    }

    public ClassPathXmlApplicationContext(String path) {
        if (StringUtils.isEmpty(path)) {
            throw new RuntimeException("配置文件没有指定");
        }
        try {
            InputStream resourceAsStream = getClass().getClassLoader().getResourceAsStream(path);
            DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
            Document document = documentBuilder.parse(resourceAsStream);

            NodeList beanList = document.getElementsByTagName("bean");
            for (int i = 0; i < beanList.getLength(); i++) {
                Node item = beanList.item(i);
                if (item.getNodeType() != Node.ELEMENT_NODE) {
                    continue;
                }
                Element beanElement = (Element) item;
                String id = beanElement.getAttribute("id");
                String aClass = beanElement.getAttribute("class");
                Class clazz = Class.forName(aClass);
                Object obj = clazz.getDeclaredConstructor().newInstance();
                hashObject.put(id, obj);
            }
            inject(beanList);

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    @Override
    public Object getBean(String id) {
        return hashObject.get(id);
    }

    /**
     * 需要在所有的类初始完后才能调用。
     *
     * @param nodeList
     */
    private void inject(NodeList nodeList) {
        for (int i = 0; i < nodeList.getLength(); i++) {
            Node itemNode = nodeList.item(i);
            if (itemNode.getNodeType() != Node.ELEMENT_NODE) {
                continue;
            }
            var item = (Element) itemNode;
            String id = item.getAttribute("id");
            NodeList childNodes = item.getChildNodes();
            for (int j = 0; j < childNodes.getLength(); j++) {
                var childNode = childNodes.item(j);
                if (childNode.getNodeType() != Node.ELEMENT_NODE || StringUtils.equals("properrty", childNode.getNodeName())) {
                    continue;
                }
                var childItem = (Element) childNode;
                String name = childItem.getAttribute("name");
                String ref = childItem.getAttribute("ref");
                var refObject = hashObject.get(ref);
                Object beanObj = hashObject.get(id);
                Class clazz = beanObj.getClass();
                try {
                    Field declaredField = clazz.getDeclaredField(name);
                    declaredField.setAccessible(true);
                    declaredField.set(beanObj, refObject);
                } catch (Exception e) {
                    e.printStackTrace();
                }

            }

        }

    }
}
